package com.iotechn.unimall.biz.service.seckill;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.iotechn.unimall.core.exception.AppServiceException;
import com.iotechn.unimall.core.exception.ExceptionDefinition;
import com.iotechn.unimall.data.domain.OrderSkuDO;
import com.iotechn.unimall.data.domain.SeckillOrderSkuDO;
import com.iotechn.unimall.data.domain.SeckillSkuDO;
import com.iotechn.unimall.data.domain.SeckillSpuDO;
import com.iotechn.unimall.data.dto.order.OrderRequestDTO;
import com.iotechn.unimall.data.dto.order.OrderRequestSkuDTO;
import com.iotechn.unimall.data.mapper.SeckillOrderSkuMapper;
import com.iotechn.unimall.data.mapper.SeckillSkuMapper;
import com.iotechn.unimall.data.mapper.SeckillSpuMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


@Service
public class SeckillSkuBizService {

    @Autowired
    private SeckillSkuMapper seckillSkuMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SeckillOrderSkuMapper seckillOrderSkuMapper;

    @Autowired
    private SeckillSpuMapper seckillSpuMapper;

    //秒杀商品缓存前缀  sku
    private final static String SECKILL_SKU_PREFIX="seck_sku_pre:";
    //秒杀商品缓存前缀    spu
    private final static String SECKILL_SPU_PREFIX="seck_spu_pre:";

    Lock lock = new ReentrantLock();


    public void makeredisCaCheSeckillSkuById(Long seckillSpuId){
        //sku 写入缓存
        List<Long> seckillSkuIdList = seckillSkuMapper.getSeckillSkuIdList(seckillSpuId);
        for (Long  seckillSkuId :seckillSkuIdList
             ) {
            SeckillSkuDO seckillSkuDO= new SeckillSkuDO();
            String seckillSkuDOJson = stringRedisTemplate.opsForValue().get(SECKILL_SKU_PREFIX+seckillSkuId);
            if(seckillSkuDOJson !=null){
                seckillSkuDO= JSONObject.parseObject(seckillSkuDOJson, SeckillSkuDO.class);
            }
            if(seckillSkuDOJson ==null){
                seckillSkuDO = seckillSkuMapper.selectById(seckillSkuId);
                String value =  JSONObject.toJSON(seckillSkuDO).toString();
                stringRedisTemplate.opsForValue().set(SECKILL_SKU_PREFIX+seckillSkuId,value,1, TimeUnit.DAYS);
            }
        }
        //spu 写入缓存
        SeckillSpuDO seckillSpuDO=new SeckillSpuDO();
        seckillSpuDO=getSeckillSpuDOCache(seckillSpuDO,seckillSpuId);
    }


    public   SeckillSkuDO selectByskuIdAndseckillSpuIdAndUpdate(Long seckillSpuId, OrderRequestSkuDTO item)  throws Exception{
        lock.lock();
        SeckillSkuDO seckillSkuDO= new SeckillSkuDO();
        try {
            //查询缓存库存
            String seckillSkuDOJson = stringRedisTemplate.opsForValue().get(SECKILL_SKU_PREFIX+item.getSeckillSkuId());
            if(seckillSkuDOJson !=null && item.getSeckillSkuId() != null){
                seckillSkuDO= JSONObject.parseObject(seckillSkuDOJson, SeckillSkuDO.class);
            }
            if(seckillSkuDOJson ==null){
                seckillSkuDO = seckillSkuMapper.selectByskuIdAndseckillSpuId(seckillSpuId, item.getSkuId());
                String value =  JSONObject.toJSON(seckillSkuDO).toString();
                stringRedisTemplate.opsForValue().set(SECKILL_SKU_PREFIX+item.getSeckillSkuId(),value,1, TimeUnit.DAYS);
            }
            //进行库存修改
            Float stockCount= seckillSkuDO.getStockCount()-item.getNum();
            if(stockCount < 0){
                throw new AppServiceException(ExceptionDefinition.ORDER_SYSTEM_BUSY);
            }
            seckillSkuDO.setStockCount(stockCount);
            seckillSkuDO.setFreeStockCount(item.getNum());
            String value =  JSONObject.toJSON(seckillSkuDO).toString();
            stringRedisTemplate.opsForValue().set(SECKILL_SKU_PREFIX+seckillSkuDO.getId(),value,1, TimeUnit.DAYS);
        } catch (Exception e) {
           throw new Exception();
        }finally {
            lock.unlock();
        }
        return seckillSkuDO;
    }

    /**
     * 根据id  获取redis中的 SeckillSkuDO
     * @param seckillskuId
     * @return
     * @throws Exception
     */
    public  SeckillSkuDO getSeckillSkuDORedis(Long seckillskuId) throws Exception {
        lock.lock();
        try {
            String seckillSkuDOJson = stringRedisTemplate.opsForValue().get(SECKILL_SKU_PREFIX+seckillskuId);
            SeckillSkuDO seckillSkuDO=new SeckillSkuDO();
            if(seckillSkuDOJson !=null){
                seckillSkuDO= JSONObject.parseObject(seckillSkuDOJson, SeckillSkuDO.class);
            }
            return seckillSkuDO;
        } catch (Exception e) {
            throw new Exception();
        }finally {
            lock.unlock();
        }
    }

    /**
     * 根据id  获取redis中的 SeckillSpuDO
     * @param seckillspuId
     * @return
     * @throws Exception
     */
    public  SeckillSpuDO getSeckillSpuDORedis(Long seckillspuId) throws Exception {
        lock.lock();
        try {
            String seckillSpuDOJson = stringRedisTemplate.opsForValue().get(SECKILL_SPU_PREFIX+seckillspuId);
            SeckillSpuDO seckillSpuDO=new SeckillSpuDO();
            if(seckillSpuDOJson !=null){
                seckillSpuDO= JSONObject.parseObject(seckillSpuDOJson, SeckillSpuDO.class);
            }
            return seckillSpuDO;
        } catch (Exception e) {
            throw new Exception();
        }finally {
            lock.unlock();
        }
    }



    public void deleteSeckillSku(Long seckillSpuId) throws Exception {
        SeckillSpuDO SeckillSpuDORedis=getSeckillSpuDORedis(seckillSpuId);
        if(SeckillSpuDORedis != null && SeckillSpuDORedis.getId() != null){
            seckillSpuMapper.updateById(SeckillSpuDORedis);
        }
        List<Long> seckillSkuIdList = seckillSkuMapper.getSeckillSkuIdList(seckillSpuId);

        for (Long seckillSkuId :seckillSkuIdList
             ) {
            SeckillSkuDO seckillSkuDORedis = getSeckillSkuDORedis(seckillSkuId);
            if (seckillSkuDORedis != null && seckillSkuDORedis.getId() != null) {
                seckillSkuMapper.updateById(seckillSkuDORedis);
            }
            stringRedisTemplate.delete(SECKILL_SKU_PREFIX+seckillSkuId);
        }
        stringRedisTemplate.delete(SECKILL_SPU_PREFIX+seckillSpuId);

    }

    /**
     * 根据seckillSpuid  获取spu关联的sku  并写入redis
     * @param seckillSpuId
     * @return
     */
    public void getSeckillSkuListBySpuId(Long seckillSpuId){
        List<SeckillSkuDO> seckillSpuIdList = seckillSkuMapper.selectList((new EntityWrapper<SeckillSkuDO>().eq("seckill_spu_id", seckillSpuId)));
        for (SeckillSkuDO seckillSkuDO :seckillSpuIdList
             ) {
            String value =  JSONObject.toJSON(seckillSkuDO).toString();
            stringRedisTemplate.opsForValue().set(SECKILL_SKU_PREFIX+seckillSkuDO.getId(),value,1, TimeUnit.DAYS);
        }
    }

    /**
     * 取消订单处理秒杀库存
     * @param orderNo
     * @param item
     */
    public void cannelSeckillSku(String orderNo, OrderSkuDO item){
        //找到订单下的 sku  和spu
        SeckillOrderSkuDO paramsosd=new SeckillOrderSkuDO();
        paramsosd.setSeckillOrderNo(orderNo);
        SeckillOrderSkuDO seckillOrderSkuDO = seckillOrderSkuMapper.selectOne(paramsosd);
        //不是秒杀订单   结束操作
        if(seckillOrderSkuDO ==null){
            return ;
        }
        SeckillSkuDO seckillSkuDO = new SeckillSkuDO();
        //redis  获取数据
        seckillSkuDO = getSeckillSkuDoCache(seckillSkuDO, seckillOrderSkuDO.getSeckillSkuId());
        SeckillSpuDO seckillSpuDO=new SeckillSpuDO();
        seckillSpuDO = getSeckillSpuDOCache(seckillSpuDO,seckillSkuDO.getSeckillSpuId());
        //修改redis 内的  库存  spu  sku
        seckillSkuDO.setStockCount(seckillSkuDO.getStockCount()+item.getNum());
        seckillSkuDO.setFreeStockCount(seckillSkuDO.getFreeStockCount()-item.getNum());
        seckillSpuDO.setStockCount(seckillSpuDO.getStockCount()+item.getNum());
        setSeckillSkuCache(seckillSkuDO);
        setSeckillSpuCache(seckillSpuDO);
    }


    /**
     * 退货订单处理秒杀库存
     * @param orderNo
     * @param item
     */
    public void refoundSeckillSku(String orderNo, OrderSkuDO item){
        //找到订单下的 sku  和spu
        SeckillOrderSkuDO paramsosd=new SeckillOrderSkuDO();
        paramsosd.setSeckillOrderNo(orderNo);
        SeckillOrderSkuDO seckillOrderSkuDO = seckillOrderSkuMapper.selectOne(paramsosd);
        SeckillSkuDO seckillSkuDO = new SeckillSkuDO();
        if(seckillOrderSkuDO != null){
        //redis  获取数据
        seckillSkuDO = getSeckillSkuDoCache(seckillSkuDO, seckillOrderSkuDO.getSeckillSkuId());
        SeckillSpuDO seckillSpuDO=new SeckillSpuDO();
        seckillSpuDO = getSeckillSpuDOCache(seckillSpuDO,seckillSkuDO.getSeckillSpuId());
        //修改redis 内的  库存  spu  sku
        Float refundNum = item.getNum()==null ? 0f:item.getNum();
        seckillSkuDO.setStockCount(seckillSkuDO.getStockCount()+refundNum);
        seckillSpuDO.setStockCount(seckillSpuDO.getStockCount()+ refundNum);
        setSeckillSkuCache(seckillSkuDO);
        setSeckillSpuCache(seckillSpuDO);
        }
    }



//    public void  refoundSeckill(String orderNo,OrderSkuDO item){
//        //退款退货修改大库库存 修改秒杀库存
//        SeckillOrderSkuDO paramsosd=new SeckillOrderSkuDO();
//        paramsosd.setSeckillOrderNo(orderNo);
//        SeckillOrderSkuDO seckillOrderSkuDO = seckillOrderSkuMapper.selectOne(paramsosd);
//        // 判断是否为秒杀订单   修改秒杀的sku 库存和 spu库存
//        if(seckillOrderSkuDO != null){
//            SeckillSkuDO seckillSkuDO = seckillSkuMapper.selectById(seckillOrderSkuDO.getSeckillSkuId());
//            seckillSkuDO.setStockCount(seckillSkuDO.getStockCount()+item.getNum());
//            seckillSkuMapper.updateById(seckillSkuDO);
//            SeckillSpuDO seckillSpuDO = seckillSpuMapper.selectById(seckillSkuDO.getSeckillSpuId());
//            seckillSpuDO.setStockCount(seckillSkuDO.getStockCount()+item.getNum());
//            seckillSpuMapper.updateById(seckillSpuDO);
//        }
//    }

    /**
     * 根据 seckillskuId 查询 seckillSkuDO  经过redis
     * @param seckillSkuDO
     * @param seckillskuId
     * @return
     */
    public SeckillSkuDO getSeckillSkuDoCache(SeckillSkuDO seckillSkuDO,Long seckillskuId){
        String seckillSkuDOJson = stringRedisTemplate.opsForValue().get(SECKILL_SKU_PREFIX+seckillskuId);
        if(seckillSkuDOJson !=null && seckillskuId != null){
            seckillSkuDO= JSONObject.parseObject(seckillSkuDOJson, SeckillSkuDO.class);
        }
        if(seckillSkuDOJson ==null){
            seckillSkuDO = seckillSkuMapper.selectById(seckillskuId);
            String value =  JSONObject.toJSON(seckillSkuDO).toString();
            stringRedisTemplate.opsForValue().set(SECKILL_SKU_PREFIX+seckillskuId,value,1, TimeUnit.DAYS);
        }
         return seckillSkuDO;
    }

    /**
     *  根据 seckillspuId 查询 seckillSpuDO  经过redis
     * @param seckillSpuDO
     * @param seckillSpuId
     * @return
     */
    public SeckillSpuDO getSeckillSpuDOCache(SeckillSpuDO seckillSpuDO,Long seckillSpuId){
        String seckillSpuDOJson = stringRedisTemplate.opsForValue().get(SECKILL_SPU_PREFIX+seckillSpuId);
        if(seckillSpuDOJson !=null && seckillSpuId != null){
            seckillSpuDO= JSONObject.parseObject(seckillSpuDOJson, SeckillSpuDO.class);
        }
        if(seckillSpuDOJson ==null){
            seckillSpuDO = seckillSpuMapper.selectById(seckillSpuId);
            String value =  JSONObject.toJSON(seckillSpuDO).toString();
            stringRedisTemplate.opsForValue().set(SECKILL_SPU_PREFIX+seckillSpuId,value,1, TimeUnit.DAYS);
        }
        return seckillSpuDO;
    }

    /**
     * seckillSkuDO 写入redis
     * @param seckillSkuDO
     */
    public void setSeckillSkuCache(SeckillSkuDO seckillSkuDO){
        String value =  JSONObject.toJSON(seckillSkuDO).toString();
        stringRedisTemplate.opsForValue().set(SECKILL_SKU_PREFIX+seckillSkuDO.getId(),value,1, TimeUnit.DAYS);

    }

    /**
     * SeckillSpuDO 写入redis
     * @param seckillSpuDO
     */
    public void setSeckillSpuCache(SeckillSpuDO seckillSpuDO){
        String value =  JSONObject.toJSON(seckillSpuDO).toString();
        stringRedisTemplate.opsForValue().set(SECKILL_SPU_PREFIX+seckillSpuDO.getId(),value,1, TimeUnit.DAYS);
    }

    /**
     * 秒杀库存 支付成功回调出路
     * @param seckillSkuDO
     */
    public void payCallBackSeckillSku(SeckillSkuDO seckillSkuDO, OrderSkuDO orderSkuDO){
        seckillSkuDO= getSeckillSkuDoCache(seckillSkuDO,seckillSkuDO.getId());
        seckillSkuDO.setFreeStockCount(seckillSkuDO.getFreeStockCount()-orderSkuDO.getNum());
        seckillSkuDO.setSalesVolume(orderSkuDO.getNum().floatValue());
        setSeckillSkuCache(seckillSkuDO);
    }

    /**
     * 秒杀库存 支付成功回调出路
     * @param seckillSpuDO
     */
    public void payCallBackSeckillSpu(SeckillSpuDO seckillSpuDO, OrderSkuDO orderSkuDO){
        seckillSpuDO= getSeckillSpuDOCache(seckillSpuDO,seckillSpuDO.getId());
        setSeckillSpuCache(seckillSpuDO);
    }
}
